﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.MountAndBlade.View.PreloadHelper
// Assembly: TaleWorlds.MountAndBlade.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 61152EB8-513B-4D4A-8AC0-0D1465C6CF6C
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\bin\Win64_Shipping_Client\TaleWorlds.MountAndBlade.View.dll

using System.Collections.Generic;
using System.Threading;
using TaleWorlds.Core;
using TaleWorlds.DotNet;
using TaleWorlds.Engine;
using TaleWorlds.Library;

#nullable disable
namespace TaleWorlds.MountAndBlade.View
{
  public class PreloadHelper
  {
    private readonly HashSet<(string, bool, bool)> _uniqueMetaMeshNames = new HashSet<(string, bool, bool)>();
    private readonly HashSet<string> _uniqueDynamicPhysicsShapeName = new HashSet<string>();
    private readonly HashSet<(MetaMesh, bool, bool)> _uniqueMetaMeshes = new HashSet<(MetaMesh, bool, bool)>();
    private readonly HashSet<ItemObject> _loadedItems = new HashSet<ItemObject>();

    public void PreloadCharacters(List<BasicCharacterObject> characters)
    {
      Utilities.EnableGlobalEditDataCacher();
      foreach (BasicCharacterObject character in characters)
      {
        foreach (Equipment allEquipment in (List<Equipment>) character.AllEquipments)
        {
          if (Mission.Current == null || Mission.Current.DoesMissionRequireCivilianEquipment || !allEquipment.IsCivilian)
            this.AddEquipment(allEquipment);
        }
        if (Mission.Current != null)
        {
          List<EquipmentElement> elementsForCharacter = Mission.Current.GetExtraEquipmentElementsForCharacter(character, true);
          if (elementsForCharacter != null)
          {
            int count = elementsForCharacter.Count;
            for (int index = 0; index < count; ++index)
              this.AddItemObject(elementsForCharacter[index].Item);
          }
        }
      }
      Utilities.DisableGlobalEditDataCacher();
      this.PreloadMeshesAndPhysics();
    }

    public void WaitForMeshesToBeLoaded()
    {
      int num;
      do
      {
        num = 0;
        foreach ((MetaMesh, bool, bool) uniqueMetaMesh in this._uniqueMetaMeshes)
          num += uniqueMetaMesh.Item1.CheckResources();
        foreach (string bodyName in this._uniqueDynamicPhysicsShapeName)
          num += (NativeObject) PhysicsShape.GetFromResource(bodyName, true) == (NativeObject) null ? 1 : 0;
        Thread.Sleep(1);
      }
      while (num != 0);
    }

    public void PreloadEquipments(List<Equipment> equipments)
    {
      foreach (Equipment equipment in equipments)
        this.AddEquipment(equipment);
      this.PreloadMeshesAndPhysics();
    }

    public void PreloadItems(List<ItemObject> items)
    {
      Utilities.EnableGlobalEditDataCacher();
      for (int index = 0; index < items.Count; ++index)
        this.AddItemObject(items[index]);
      Utilities.DisableGlobalEditDataCacher();
      this.PreloadMeshesAndPhysics();
    }

    private void AddEquipment(Equipment equipment)
    {
      for (int index = 0; index < 12; ++index)
      {
        ItemObject itemObject = equipment.GetEquipmentFromSlot((EquipmentIndex) index).Item;
        if (itemObject != null)
          this.AddItemObject(itemObject);
      }
    }

    private void AddItemObject(ItemObject item)
    {
      if (item == null)
        return;
      bool isUsingTableau = item.IsUsingTableau;
      bool isUsingTeamColor = item.IsUsingTeamColor;
      this.RegisterMetaMeshUsageIfValid(item.MultiMeshName, isUsingTableau, isUsingTeamColor);
      this.RegisterMetaMeshUsageIfValid(item.HolsterMeshName, isUsingTableau, isUsingTeamColor);
      if (item.WeaponComponent != null)
      {
        if (item.IsCraftedWeapon)
        {
          this.RegisterMetaMeshUsageIfValid(item.GetHolsterWithWeaponMeshIfExists(), isUsingTableau, isUsingTeamColor);
          this.RegisterMetaMeshUsageIfValid(item.GetHolsterMeshIfExists(), isUsingTableau, isUsingTeamColor);
          this.RegisterMetaMeshUsageIfValid(item.GetFlyingMeshIfExists(), isUsingTableau, isUsingTeamColor);
        }
        else
        {
          this.RegisterMetaMeshUsageIfValid(item.HolsterWithWeaponMeshName, isUsingTableau, isUsingTeamColor);
          this.RegisterMetaMeshUsageIfValid(item.HolsterMeshName, isUsingTableau, isUsingTeamColor);
          this.RegisterMetaMeshUsageIfValid(item.FlyingMeshName, isUsingTableau, isUsingTeamColor);
        }
      }
      else if (item.HasHorseComponent)
      {
        foreach (KeyValuePair<string, bool> additionalMeshesName in item.HorseComponent.AdditionalMeshesNameList)
          this.RegisterMetaMeshUsageIfValid(additionalMeshesName.Key, isUsingTableau, isUsingTeamColor);
      }
      else if (item.HasArmorComponent && !string.IsNullOrEmpty(item.ArmorComponent.ReinsMesh))
      {
        this.RegisterMetaMeshUsageIfValid(item.ArmorComponent.ReinsMesh, isUsingTableau, isUsingTeamColor);
        this.RegisterMetaMeshUsageIfValid(item.ArmorComponent.ReinsRopeMesh, isUsingTableau, isUsingTeamColor);
      }
      if (!this._loadedItems.Contains(item))
      {
        this.RegisterMetaMeshUsageIfValid(item.GetMultiMesh(false, false, true), isUsingTableau, isUsingTeamColor);
        if (item.HasArmorComponent)
        {
          this.RegisterMetaMeshUsageIfValid(item.GetMultiMesh(false, true, true), isUsingTableau, isUsingTeamColor);
          this.RegisterMetaMeshUsageIfValid(item.GetMultiMesh(true, false, true), isUsingTableau, isUsingTeamColor);
          this.RegisterMetaMeshUsageIfValid(item.GetMultiMesh(true, true, true), isUsingTableau, isUsingTeamColor);
        }
        this._loadedItems.Add(item);
      }
      this.RegisterPhysicsBodyUsageIfValid(this._uniqueDynamicPhysicsShapeName, item.CollisionBodyName);
      this.RegisterPhysicsBodyUsageIfValid(this._uniqueDynamicPhysicsShapeName, item.BodyName);
      this.RegisterPhysicsBodyUsageIfValid(this._uniqueDynamicPhysicsShapeName, item.HolsterBodyName);
    }

    private void PreloadMeshesAndPhysics()
    {
      foreach ((MetaMesh, bool, bool) uniqueMetaMesh in this._uniqueMetaMeshes)
      {
        MetaMesh metaMesh = uniqueMetaMesh.Item1;
        metaMesh.PreloadForRendering();
        metaMesh.PreloadShaders(uniqueMetaMesh.Item2, uniqueMetaMesh.Item3);
      }
      foreach (string bodyName in this._uniqueDynamicPhysicsShapeName)
        PhysicsShape.AddPreloadQueueWithName(bodyName, new Vec3(1f, 1f, 1f));
      PhysicsShape.ProcessPreloadQueue();
    }

    public void Clear()
    {
      this._uniqueMetaMeshNames.Clear();
      this._uniqueDynamicPhysicsShapeName.Clear();
      this._uniqueMetaMeshes.Clear();
      PhysicsShape.UnloadDynamicBodies();
    }

    private void RegisterMetaMeshUsageIfValid(
      string metaMeshName,
      bool useTableau,
      bool useTeamColor)
    {
      (string, bool, bool) valueTuple = (metaMeshName, useTableau, useTeamColor);
      if (string.IsNullOrEmpty(metaMeshName) || this._uniqueMetaMeshNames.Contains(valueTuple))
        return;
      this.RegisterMetaMeshUsageIfValid(MetaMesh.GetCopy(metaMeshName, false, true), useTableau, useTeamColor);
      this._uniqueMetaMeshNames.Add(valueTuple);
    }

    private void RegisterMetaMeshUsageIfValid(
      MetaMesh metaMesh,
      bool useTableau,
      bool useTeamColor)
    {
      if (!((NativeObject) metaMesh != (NativeObject) null))
        return;
      this._uniqueMetaMeshes.Add((metaMesh, useTableau, useTeamColor));
    }

    private void RegisterPhysicsBodyUsageIfValid(
      HashSet<string> uniquePhysicsShapeName,
      string physicsShape)
    {
      if (string.IsNullOrWhiteSpace(physicsShape))
        return;
      uniquePhysicsShapeName.Add(physicsShape);
    }
  }
}
